package org.amse.korovkin.ciphering.model.cipher.monocipher;
import java.io.*;
import java.util.zip.DataFormatException;
import org.amse.korovkin.ciphering.model.Statistic;
import org.amse.korovkin.ciphering.model.TableOfFrequency;
import org.amse.korovkin.ciphering.model.cipher.ICipher;
import org.amse.korovkin.ciphering.model.cipher.IKey;
import org.amse.korovkin.ciphering.model.cipher.util.TextWork;

public class MonoCipher implements ICipher{
    private static ICipher cipher = null;
    private final String name = "MonoAlphabet";

    private MonoCipher() {
    }
    public static ICipher getInstance() {
        if (cipher == null) {
            cipher = new MonoCipher();
        }
        return cipher;
    }

    public String getName() {
        return this.name;
    }

    public void encrypt(String inFile, String outFile, String keyFile)
            throws IOException, ArrayIndexOutOfBoundsException{
        ChangeTable keyTable = new ChangeTable();        
        inFile = TextWork.cutComma(inFile);
        outFile = TextWork.cutComma(outFile);
        try {
            keyTable.readFromFile(keyFile);
        } catch (IOException e) {
            throw new IOException("Cann't find keyFile.");
        }
        encrypt(inFile, outFile, keyTable);
    }

    public void encrypt(String inFile, String outFile, IKey key)
            throws FileNotFoundException, IOException {
        int i;
        ChangeTable keyTable = (ChangeTable)key;
        try {
            FileReader fReader = new FileReader(inFile);
            try {
                FileWriter fWriter = new FileWriter(outFile);
                while ((i = fReader.read()) != -1) {
                    char ch = (char) i;
                    int exchange = keyTable.getLetter2(ChangeTable.toLowerCase(ch));
                    if (exchange != -1) {
                        if (ch >= 'A' && ch <= 'Z') {
                            fWriter.write(ChangeTable.toUpperCase((char) exchange));
                            continue;
                        } else {
                            fWriter.write((char) keyTable.getLetter2(ch));
                            continue;
                        }
                    } else {
                        fWriter.write((char) i);
                    }
                }
                fReader.close();
                fWriter.close();
            } catch (IOException e) {
                throw new IOException("Cann't find File for encryptedText.");
            }
        } catch (IOException e) {
            throw new IOException("Cann't find sourceFile for encrypt.");
        }
    }

    public void decrypt(String inFile, String outFile, String keyFile)
            throws IOException, ArrayIndexOutOfBoundsException{
        ChangeTable keyTable = new ChangeTable();       
        inFile = TextWork.cutComma(inFile);
        outFile = TextWork.cutComma(outFile);
        try {
            keyTable.readFromFile(keyFile);
        } catch (IOException e) {
            throw new IOException("Cann't find keyFile.");
        }
        decrypt(inFile, outFile, keyTable);
    }

    public void decrypt(String inFile, String outFile, IKey key)
            throws FileNotFoundException, IOException {
        int i;
        ChangeTable keyTable = (ChangeTable)key;
        try {
            FileReader fReader = new FileReader(inFile);
            try {
                FileWriter fWriter = new FileWriter(outFile);
                while ((i = fReader.read()) != -1) {
                    char ch = (char) i;
                    int exchange = keyTable.getLetter1(ChangeTable.toLowerCase(ch));
                    if (exchange != -1) {
                        if (ch >= 'A' && ch <= 'Z') {
                            fWriter.write(ChangeTable.toUpperCase((char) exchange));
                            continue;
                        } else {
                            fWriter.write((char) exchange);
                            continue;
                        }
                    } else {
                        fWriter.write((char) i);
                    }
                }
                fReader.close();
                fWriter.close();
            } catch (IOException e) {
                throw new IOException("Cann't find File for decryptedText.");
            }
        } catch (IOException e) {
            throw new IOException("Cann't find sourceFile for decrypt.");
        }
    }

    public void attack(String inFile, String outFile)
            throws IOException, DataFormatException, InterruptedException {
        MonoAttacker.attack(inFile, outFile);
    }

}
